package creational.singleton;

import lombok.extern.slf4j.Slf4j;
import org.junit.Test;
import creational.singleton.lazyman.LazyManSingleton4;

import java.io.*;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;

/**
 * @author binbin
 * @since 2022/10/4 19:31
 */
@Slf4j
public class TryDestroy {

    /**
     * 使用反射破坏单例
     * <p>
     * 解决方法: 见LazyManSingleton3的无参构造
     *
     * @throws NoSuchMethodException
     * @throws InvocationTargetException
     * @throws InstantiationException
     * @throws IllegalAccessException
     */
    @Test
    public void reflect() throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
        Class<LazyManSingleton4> clazz = LazyManSingleton4.class;
        reflect(clazz);
    }

    /**
     * 使用反序列化破坏单例
     *
     * 解决方法: 见LazyManSingleton4的readResolve方法
     * @throws IOException
     * @throws ClassNotFoundException
     */
    @Test
    public void serialize() throws IOException, ClassNotFoundException {
        LazyManSingleton4 instance1 = LazyManSingleton4.getInstance();
        Path path = Paths.get("/serialization");
        ObjectOutputStream oos = new ObjectOutputStream(Files.newOutputStream(path));
        oos.writeObject(instance1); //writeObject(Object obj)的参数类型必须实现Serializable接口
        oos.close();

        ObjectInputStream ois = new ObjectInputStream(Files.newInputStream(path));
        LazyManSingleton4 instance2 = (LazyManSingleton4) ois.readObject();

        log.info("{} {}, {}", instance1, instance2, instance1 == instance2);
    }

    private <T> void reflect(Class<T> clazz) throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
        Constructor<T> noArgsConstructor = clazz.getDeclaredConstructor();
        noArgsConstructor.setAccessible(true);
        T instance1 = noArgsConstructor.newInstance();
        T instance2 = noArgsConstructor.newInstance();

        log.info("{} {}, {}", instance1, instance2, instance1 == instance2);
    }
}
